package com.tms.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tms.admin.checkUtil.DataCheck;
import com.tms.admin.entity.TmsCustomer;
import com.tms.admin.entity.TmsDriver;
import com.tms.admin.entity.TmsLogistics;
import com.tms.admin.entity.enums.LogisticStatusEnum;
import com.tms.admin.entity.enums.LogisticsGetStatusEnum;
import com.tms.admin.entity.vo.LogisticDetailVO;
import com.tms.admin.entity.vo.LogisticsQueryVO;
import com.tms.admin.handler.TMSException;
import com.tms.admin.service.TmsCustomerService;
import com.tms.admin.service.TmsDriverService;
import com.tms.admin.service.TmsLogisticsService;
import com.tms.admin.mapper.TmsLogisticsMapper;
import com.tms.common.entity.ResultCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author 86132
* @description 针对表【tms_logistics】的数据库操作Service实现
* @createDate 2022-09-06 21:19:13
*/
@Service
public class TmsLogisticsServiceImpl extends ServiceImpl<TmsLogisticsMapper, TmsLogistics>
    implements TmsLogisticsService{

    @Autowired
    private TmsDriverService driverService;

    @Autowired
    private TmsCustomerService customerService;

    /**
     * 物流信息分页/模糊查询
     * @param logisticsQueryVO
     */
    @Override
    public Map<String, Object> getPageByCondition(LogisticsQueryVO logisticsQueryVO) {
        /**
         * Step 1. 根据 VO 类, 取出里面所有的查询条件
         *
         * Step 2. 根据查询条件来封装 Wrapper
         *
         * Step 3. 执行分页查询, 获取到 Page 对象
         *
         * Step 4. 将 Page 对象 封装到 Map
         */
        // Step 1 取出查询条件
        String logistic_code = logisticsQueryVO.getCode();
        String logistic_type = logisticsQueryVO.getType();
        String logistic_company = logisticsQueryVO.getCompany();
        boolean logistic_showAll = logisticsQueryVO.isShowAll();
        if (logistic_code == null) logistic_code = "";
        if (logistic_type == null) logistic_type = "";
        if (logistic_company == null) logistic_company = "";

        Integer pageNum = logisticsQueryVO.getPageNum();
        Integer pageSize = logisticsQueryVO.getPageSize();
        // Step 2
        LambdaQueryWrapper<TmsLogistics> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(TmsLogistics::getCode,logistic_code)
                    .like(TmsLogistics::getType,logistic_type)
                    .like(TmsLogistics::getCompany,logistic_company);
        // 若不显示已出库，就只搜索未签收的物流
        if(!logistic_showAll) queryWrapper.like(TmsLogistics::getGetStatus, LogisticsGetStatusEnum.NO.getName());
        // Step 3
        // 创建分页对象——page,初始化分页大小和页数
        if (pageNum == null){
            pageNum = 1;
        }
        if (pageSize == null){
            pageSize = 5;
        }
        Page<TmsLogistics> logisticsPage = new Page<>(pageNum,pageSize);
        baseMapper.selectPage(logisticsPage,queryWrapper);
        // Step 4
        Map<String,Object> pageInfoMap = new HashMap<>();
        pageInfoMap.put("logisticsList",logisticsPage.getRecords());
        pageInfoMap.put("pageNum",logisticsPage.getCurrent());
        pageInfoMap.put("pageSize",logisticsPage.getSize());
        pageInfoMap.put("total",logisticsPage.getTotal());
        pageInfoMap.put("hasNext",logisticsPage.hasNext());
        pageInfoMap.put("hasPrevious",logisticsPage.hasPrevious());
        return pageInfoMap;
    }

    /**
     * 新增物流信息
     * @param logistics
     */
    @Override
    public void addLogistic(TmsLogistics logistics) {
        /**
         * Step 1. 根据 logistic 获取 idFrom, idTo, driverId,type, name, compony
         *
         * Step 2. 判断上面获取的信息是否为null, 若为null则抛出异常
         *
         * Step 3. 判断 tms_customer表是否存在id分别为 idFrom 和 idTo 的记录,  不存在则抛出异常
         *
         * Step 4. 根据 logistic 获取 driverId
         *
         * Step 5. 判断 tms_driver表是否存在id分别为 driverId 的记录, 不存在则抛出异常
         *
         * Step 6. 保存 logistic 到 tms_logistic 表
         */
        // Step 1-2 物流信息必填项非空判断
        logistics.setStatus(LogisticStatusEnum.WAITING.getName());
        logistics.setGetStatus(LogisticsGetStatusEnum.NO.getName());
        if (DataCheck.isNullToLogistic(logistics)){
            throw new TMSException(ResultCode.ERROR,"请输入完整物流信息");
        }
        // 判断物流单号是否重复——根据新增的物流单号，取数据库里查询是否存在一样单号的记录
        LambdaQueryWrapper<TmsLogistics> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TmsLogistics::getCode,logistics.getCode());
        if (baseMapper.selectOne(queryWrapper) != null){
            throw new TMSException(ResultCode.ERROR,"快递单号已存在");
        }
        // Step 3-5 判断司机、收件人、寄件人是否存在
        if (customerService.getById(logistics.getCustomerIdFrom()) == null){
            throw new TMSException(ResultCode.ERROR,"收件人不存在");
        }
        if (customerService.getById(logistics.getCustomerIdTo()) == null){
            throw new TMSException(ResultCode.ERROR,"寄件人不存在");
        }
        if (driverService.getById(logistics.getDriverId()) == null){
            throw new TMSException(ResultCode.ERROR,"司机不存在");
        }
        // Step 6
        baseMapper.insert(logistics);
    }

    @Override
    public void removeLogisticsById(List<Integer> logisticsIds) {
        /**
         * Step 1. 判断 入参 logisticsIds 是否为空, 为空则直接返回 ture
         *
         * Step 2 判断物流是否到达
         *
         * Step 3. 循环遍历 driversIds, 调用 DAO 层的删除方法
         *
         */
        // Step 1
        if (logisticsIds == null || logisticsIds.isEmpty()){
            throw new TMSException(ResultCode.FAIL,"当前物流不存在");
        }
        // Step 2 判断是否有未完成的物流订单
        for (Integer id : logisticsIds) {
            TmsLogistics logistic = baseMapper.selectById(id);
            if (!"已送达".equals(logistic.getStatus())){
                throw new TMSException(ResultCode.ERROR,"物流单号为"+logistic.getCode()+"的货物还未送达!");
            }
        }
        for (Integer id : logisticsIds) {
            baseMapper.updateGetStatus(id, true);
        }
    }

    @Override
    public void modifyLogisticsById(TmsLogistics logistics) {
        /**
         * Step 1. 判断 logistics的 id 是否为空，若为空则抛出异常
         *
         * Step 2. 获取 logistics 的 fromId, toId, driverId
         *
         * Step 3. 若 fromId 不为空 则判断 表tms_customer 是否有 id=fromId 的记录, 没有则抛出异常1
         *
         * Step 4. 若 toId 不为空 则判断 表tms_customer 是否有 id=toId 的记录, 没有则抛出异常1
         *
         * Step 5. 若  driverId 不为空, 则判断 表tms_driver 是否有 id=driverId 的记录，没有则抛出异常2
         *
         * Step 6. 调用 DAO 层方法, 根据 logistics 的 id 修改非空的信息, 保存到 表tms_logistic
         */
        // Step 1 各字段完整性、逻辑检验
        Integer id = logistics.getId();
        // id 不能为空
        if (id == null){
            throw new TMSException(ResultCode.ERROR,"ID不存在，无法修改");
        }
        // 数据库需存在该物流记录
        TmsLogistics tmsLogistics = baseMapper.selectById(id);
        if (tmsLogistics == null){
            throw new TMSException(ResultCode.ERROR,"不存在该物流，无法修改");
        }
        // 快递单号不能被修改
        if (!tmsLogistics.getCode().equals(logistics.getCode())){
            throw new TMSException(ResultCode.ERROR,"快递单号不允许修改");
        }
        // 判断物流各时间的规范、已经运输和取件状态的转换是否正确
        String checkResult = DataCheck.checkLogistic(logistics);
        if (!"success".equals(checkResult)){
            throw new TMSException(ResultCode.ERROR,checkResult);
        }
        // 判断收件人是否存在
        if (customerService.getById(logistics.getCustomerIdFrom()) == null){
            throw new TMSException(ResultCode.ERROR,"收件人不存在");
        }
        // 判断寄件人是否存在
        if (customerService.getById(logistics.getCustomerIdTo()) == null){
            throw new TMSException(ResultCode.ERROR,"寄件人不存在");
        }
        // 判断司机是否存在
        if (driverService.getById(logistics.getDriverId()) == null){
            throw new TMSException(ResultCode.ERROR,"司机不存在");
        }
        // 都无误 更新数据
        baseMapper.updateById(logistics);

    }

    @Override
    public LogisticDetailVO getLogisticById(Integer logisticsId) {
        /**
         * Step 1. 判断 logisticsId id 是否为空，若为空则抛出异常
         *
         * Step 2. 调用 DAO 层方法，查询 tms_logistics表中 id = logisticsId 的记录, 赋值为 logistics
         *
         * Step 3. 判断 查询的 logistics 是否为空, 为空则抛出异常
         *
         * Step 4. 根据 logistics 获取 fromId, toId, driverId
         *
         * Step 5. 查询表tms_customer中 id分别为fromId, toId的记录, 分别作为发货顾客和收货顾客
         *
         * Step 6. 查询表tms_driver中 id 为 driverId 的记录，作为物流详情的司机
         *
         * Step 7. 将 logistics 的 id, company, startTime, arrivedTime, getStatus和getTime拷贝到要返回的VO对象中。
         *
         * Step 8. 返回 VO 对象
         */
        // Step 1
        if (logisticsId == null){
            throw new TMSException(ResultCode.ERROR,"物流ID不存在");
        }
        // Step 2-3
        TmsLogistics logistic = baseMapper.selectById(logisticsId);
        if (logistic == null){
            throw new TMSException(ResultCode.ERROR,"不存在该物流信息，无法查看");
        }
        // Step 4-6
        TmsCustomer fromCustomer = customerService.getById(logistic.getCustomerIdFrom());
        TmsCustomer toCustomer = customerService.getById(logistic.getCustomerIdTo());
        TmsDriver driver = driverService.getById(logistic.getDriverId());
        // 对查询到的司机、顾客非空判断
        if (fromCustomer == null) throw new TMSException(ResultCode.ERROR,"不存在此寄件人");
        if (toCustomer == null) throw new TMSException(ResultCode.ERROR,"不存在此收件人");
        if (driver == null) throw new TMSException(ResultCode.ERROR,"不存在此司机");
        // Step 7-8
        LogisticDetailVO resultVO = new LogisticDetailVO();
        resultVO.setCode(logistic.getCode());
        resultVO.setToCustomer(toCustomer);
        resultVO.setFromCustomer(fromCustomer);
        resultVO.setCompany(logistic.getCompany());
        resultVO.setStartTime(logistic.getStartTime());
        resultVO.setArrivedTime(logistic.getArrivedTime());
        resultVO.setStatus(logistic.getStatus());
        resultVO.setGetStatus(logistic.getGetStatus());
        resultVO.setGetTime(logistic.getGetTime());
        resultVO.setDriver(driver);
        resultVO.setName(logistic.getName());
        resultVO.setType(logistic.getType());
        return resultVO;
    }
}




